import type { Directive, DirectiveBinding } from 'vue'

interface ElType extends HTMLElement {
  __handleClick__: () => void
  __handleKeyDown__: (e: KeyboardEvent) => void
  disabled: boolean
}

/*
  需求：防止按钮在短时间内被多次点击，使用节流函数限制规定时间内只能点击一次。

  思路：
    1、第一次点击，立即调用方法并禁用按钮，等延迟结束再次激活按钮
    2、将需要触发的方法绑定在指令上
  
  使用：给 Dom 加上 v-throttle 及回调函数即可
  <button v-throttle="debounceClick">节流提交</button>
*/

export const throttle: Directive = {
  /**
   * 定义了一个名为mounted的指令安装函数，用于在元素挂载时处理特定逻辑
   * @param el 指令绑定的元素，类型为ElType
   * @param binding 包含指令相关信息的对象，包括指令的值、参数等
   */
  mounted(el: ElType, binding: DirectiveBinding) {
    // 检查指令的值是否为函数类型，若不是则抛出错误
    if (typeof binding.value !== 'function') {
      throw 'callback must be a function'
    }
    // 定义一个用于存储定时器的变量，初始值为null
    let timer: number | null = null
    el.__handleClick__ = () => {
      // 如果存在一个未执行完的定时器，清除它
      if (timer) {
        clearInterval(timer)
      }
      // 检查元素是否被禁用，如果没有则进行处理
      if (!el.disabled) {
        // 将元素设为禁用状态，防止重复点击
        el.disabled = true
        // 执行指令绑定的函数
        binding.value()
        // 设置一个定时器，在1秒后将元素的禁用状态恢复
        timer = setTimeout(() => {
          el.disabled = false
        }, 1500)
      }
    }
    // 处理键盘事件，绑定回车键
    el.__handleKeyDown__ = (e: KeyboardEvent) => {
      if (e.key === 'Enter') {
        el.__handleClick__()
      }
    }

    el.addEventListener('click', el.__handleClick__)
    el.addEventListener('keydown', el.__handleKeyDown__)
  },
  /**
   * 在组件卸载前，移除点击事件监听器
   *
   * 此方法的目的是为了在组件卸载时，避免内存泄漏或不必要的事件监听器留在DOM中
   * 通过移除事件监听器，可以帮助确保应用的性能和内存管理处于最优状态
   *
   * @param el - ElType类型的元素，表示需要处理的DOM节点
   *             我们在此处移除此节点上绑定的特定点击事件监听器
   */
  beforeUnmount(el: ElType) {
    el.removeEventListener('click', el.__handleClick__)
    el.removeEventListener('keydown', el.__handleKeyDown__)
  },
}
